package controller

import (
	"encoding/base64"
	"strings"
	"sync"
	"time"

	"device-admin/internal/app/grpc/protoc/robotc"
	"device-admin/internal/app/grpc/service/pubsub"
	"device-admin/internal/app/web/service/cmd"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"192.168.1.75/go-pkg/response"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/samber/lo"
	"google.golang.org/protobuf/proto"
)

type CMD struct{}

// wildmsg返回
type WildMsgRes struct {
	RobotID string `json:"robot_id"`
	Data    string `json:"data"`
}

// WildMsg
func (CMD) WildMsg(c *gin.Context) {
	var params struct {
		RobotID string `json:"robot_id"`
		WildMsg string `json:"wildMsg"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	dataBytes, err := base64.StdEncoding.DecodeString(params.WildMsg)
	if err != nil {
		response.JSON(c, nil, errorx.New("无效的wildmsg", -1))
		return
	}
	wilgmsg := &robotc.WildMsg{}
	err = proto.Unmarshal(dataBytes, wilgmsg)
	if err != nil {
		response.JSON(c, nil, errorx.New("wildmsg格式有误", -1))
		return
	}
	// 批量操作
	robotArray := strings.Split(params.RobotID, ",")
	robotArray = lo.Uniq(robotArray) // 去重
	// 结果返回
	wildmsgRes := []WildMsgRes{}
	// 失败的robotID集合
	faildRobotIDs := []string{}
	// 并发控制
	var wg sync.WaitGroup
	wg.Add(len(robotArray))
	// 批量下发，并等待全部响应结果
	for _, robotID := range robotArray {
		go func(robotID string) {
			defer wg.Done()
			msgID := "waitmsg_" + helper.RandString(16)
			wilgmsg.FromID = "server"
			wilgmsg.ToID = "95"
			wilgmsg.StrGUID = msgID
			data, _ := proto.Marshal(wilgmsg)
			pubsub.CMDPublish(robotID, "95", "wildmsg", base64.StdEncoding.EncodeToString(data))
			// 等待执行的结果
			resData, err := cmd.WaitCmdRsp(robotID, "wildmsg", msgID, "95")
			if err != nil {
				// 失败的设备列表
				faildRobotIDs = append(faildRobotIDs, robotID)
			} else {
				// 成功的结果数组
				wildmsgRes = append(wildmsgRes, WildMsgRes{
					RobotID: robotID,
					Data:    base64.StdEncoding.EncodeToString(resData),
				})
			}
		}(robotID)
		time.Sleep(time.Millisecond * time.Duration(50))
	}
	wg.Wait()
	// 命令回调
	cmdCallback(params.RobotID, wilgmsg.BodyType)
	// 失败的设备
	if len(faildRobotIDs) > 0 {
		faildRobotIDsStr := strings.Join(faildRobotIDs, ",")
		response.JSON(c, wildmsgRes, errorx.New("设备"+faildRobotIDsStr+"操作失败", -1))
	} else {
		// 单个结果
		if len(robotArray) == 1 {
			response.JSON(c, map[string]string{
				"data": wildmsgRes[0].Data,
			}, err)
			// 多个结果
		} else if len(robotArray) > 1 {
			response.JSON(c, wildmsgRes, nil)
		}
	}
}

// cmdCallback 命令回调
func cmdCallback(robotID, msgType string) {
	switch msgType {
	// 开关机计划更新
	case string((&robotc.ReqSwitchMachineConfig{}).ProtoReflect().Descriptor().FullName()):
		reqSwitchMachineConfig := &robotc.ReqSwitchMachineConfig{}
		reqSwitchMachineConfig.OptType = 0 // 获取数据
		msgContent, _ := proto.Marshal(reqSwitchMachineConfig)
		wm := &robotc.WildMsg{}
		wm.FromType = robotc.WildMsg_eMobileServiceClient
		wm.FromID = "server"
		wm.ToType = robotc.WildMsg_eMonitorClient
		wm.ToID = "95"
		wm.BodyType = msgType
		wm.BodyContent = msgContent
		protoBytes, _ := proto.Marshal(wm)
		pubsub.CMDPublish(robotID, "95", "wildmsg", base64.StdEncoding.EncodeToString(protoBytes))
	}
}
